package quirk;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Communicates with the Index to get the necessary
 * data for each QUIRK command
 * 
 * @author Andrew Bernard
 */
public class IndexManager {   
  private Index index = null; 
  private List results = null;
  private int retrievalRequests = 0;
  private int truePositive = 0;
  
  /**
   * Constructor. Creates a new instance of Index
   */
  public IndexManager() {
    index = new Index();
    results = new ArrayList();
  }
  
  private class Result {
    public String fileName;
    public int lineNum;
    
    public Result(String fileName, int lineNum) {
      
      
      this.fileName = fileName;
      this.lineNum = lineNum;
    }
    
    public String toString() {
      return "<" + lineNum + ", " + fileName + ">";
    }
  }
  
  public void statsCommand() {
    StringBuffer stats = new StringBuffer();
    stats.append("\n-------- Corpus Files --------");
    
    List dataHeaderList = index.getDataHeaderList();
    Iterator itr = dataHeaderList.iterator();
    while(itr.hasNext()) {
      Index.DataHeader dataHeader = (Index.DataHeader)itr.next();
      stats.append("\n\nFile name: "+dataHeader.fileName)
           .append("\nCharacters: "+dataHeader.charsInFile)
           .append("\nWords: "+dataHeader.wordsInFile)
           .append("\nLines: "+dataHeader.linesInFile);
    }
    
    Index.Summary summary = index.getSummary();
    stats.append("\n\n-------- Corpus Summary --------\n")
         .append("Characters: " + summary.charsInCorpus + "\n")
         .append("Words: " + summary.wordsInCorpus + "\n")
         .append("Lines: " + summary.linesInCorpus + "\n")
         .append("Files: " + summary.filesInCorpus);
    outln(stats.toString());
  }
  
  public void indexCommand() {
    outln("INDEX? What index? Look it up yourself :p");
  }
  
  public void queryCommand(String query) throws IOException {
    Query q = new Query(query);
    List wordsInQuery = getQueryWords(query);
    List dataHeaderList = index.getDataHeaderList();
    applyQueryPattern(q, wordsInQuery, dataHeaderList);
  }
  
  /**
   * This method does the following:
   *    1. Create a QueryWord object for each word in the query
   *    2. For each line in the index, set the word object to true or false if it exists in the line
   *    3. Apply the query pattern to each set of word objects for each line
   *    4. Store the results if the query returns a match
   * @param q the Query object used to evaluate the query
   * @param wordsInQuery a List of words (as String objects) in the query
   * @param dataHeaderList a List of the data headers (Index.DataHeader) in the index
   */
  private void applyQueryPattern(Query q, List wordsInQuery, List dataHeaderList) {
    Iterator itrData = dataHeaderList.iterator();
    while(itrData.hasNext()) {
      Index.DataHeader dataHeader = (Index.DataHeader)itrData.next();      
      index.setPosition(dataHeader.dataStartPos);
      
      int linesToSkip = 0;
      for(int lineNum = 0; lineNum < dataHeader.linesInFile; lineNum++) {
        int filter = (int)index.getValue(dataHeader.lineFilterLen);
        QueryWord[] lineWordMap = new QueryWord[wordsInQuery.size()];
        
        for(int w = 0; w < wordsInQuery.size(); w++) {
          String word = wordsInQuery.get(w).toString().toLowerCase();
          boolean wordFound = false;
          
          boolean foundPossibleMatch = index.isWordOnLine(filter, lineNum, word);          
          if(foundPossibleMatch) {
            retrievalRequests++;
            BufferedReader fileReader = dataHeader.getFileInput();
            String line = Util.getLineFromStream(fileReader, linesToSkip).toLowerCase();
            wordFound = isWordInLine(word, line);
            if(wordFound) truePositive++;
            linesToSkip = 0;
          }
          else
            linesToSkip++;
          
          lineWordMap[w] = new QueryWord(word, wordFound);
        }
        
        boolean queryMatch = q.evaluate(lineWordMap);
        if(queryMatch) {
          Result r = new Result(dataHeader.fileName, lineNum);
          results.add(r);
        }
      }      
    }
  }
    
  private boolean isWordInLine(String word, String line) {
    boolean isWordInLine = false;
    char[] breakChars = index.getBreakCharArray();
    for(int c = 0; c < breakChars.length; c++) {
      String test = word + breakChars[c];
      isWordInLine = line.indexOf(test) > 0;
      if(isWordInLine) break;
    }
    return isWordInLine;
  }
  
  /**
   * Returns a list of the words in the query as string objects. 
   * @throws IOException
   */
  private List getQueryWords(String query) throws IOException {
    ArrayList words = new ArrayList();
    StringReader reader = new StringReader(query);
    String wordText = "";
    
    for(int ch = reader.read(); ch != Constants.EOF; ch = reader.read()) {
      if(index.isBreakCharacter(ch) || Query.isGrammar(ch))
        if(wordText.length() > 0)
          words.add(wordText);
      else
        wordText += (char)ch;
    }
    return words;
  }
  
  public void refineCommand(String refined) {
    outln(refined + " ... dude, make up your mind!");
  }
  
  public void showCommand() {
    outln("SHOW ME THE MONEY!!!");
  }
  
  public void nextCommand() {
    outln("NEXT project, I'm hiring a PM");
  }
  
  public void quitCommand() {
    outln("quitting...show quirk stats");
  }
  /** This is here because I'm lazy ;) */
  private static void outln(String text) {
    System.out.println(text);
  }
}
